% Class "RotaryEncoder"
%
% *Methods*
% - getX
% - getY
% - getXY
% - getXYt
% - resetX
% - resetY
% - resetXY
%
%
% *Example*
% 
% When you're really done, close the object. This will close and cleanup all the
% references to the serial port.
%
%  Wheel = RotaryEncoder('com1');
% 
%  [x, y] = Wheel.getXY();
%  ... do more stuff here
%  ...
%
%  Wheel.close();
%
%
% If called with an empty com port string, no serial connection will be
% established. The serial commands will be echo'd to stdout:
%
%  Wheel = RotaryEncoder('')
%  ...
%
%
% *Protocol*
% Custom protocol for the RotaryEncoder controller:
%
% x -> Get X coordinate
% y -> Get Y coordinate
% z -> Get both X and Y coordinates seperated by a comma
% a -> Get X, Y and the time in miliseconds, seperated by a comma            
%
% X -> Resets the X coordinate (x = 0)
% Y -> Resets the Y coordinate (y = 0)
% Z -> Resets both the X and Y coordinate
%
% t -> Toggle test mode. In test mode, every 50 miliseconds a coordinate will
%      be sent. Send another 't' to stop.


classdef RotaryEncoder
    
    properties (SetAccess = public)
        serobj;
        debugmode = false;
    end
    
    methods
        function RE = RotaryEncoder(comport)
            if (strcmp(comport, ''))
                fprintf('RotaryEncoder: No Com port given, running in debug mode...\n')
                RE.debugmode = true;
            end
            
            if (not(RE.debugmode))
                delete(instrfind);
                RE.serobj = serial(comport);
                
                % serial port configuration
                set(RE.serobj, 'Baudrate',        115200);
                set(RE.serobj, 'Parity',          'none');
                set(RE.serobj, 'Databits',        8);       % number of data bits
                set(RE.serobj, 'StopBits',        1);       % number of stop bits
                set(RE.serobj, 'Terminator',      'CR/LF'); % line ending character
                % see also:
                % http://www.mathworks.com/matlabcentral/newsreader/view_original/292759
                
                %set(RE.serobj, 'InputBufferSize', 1);       % set read buffBuffer for read
                set(RE.serobj, 'FlowControl',     'none');   %
                
                % open the serial port
                fopen(RE.serobj);
                
                % since matlab pulls the DTR line, the arduino will reset
                % so we have to wait for the initialization of the controller
                oldState = pause('query');
                pause on;
                pause(2.5);
                pause(oldState);
                
                % firmware responds with 'ready!'
                status = RE.receive();
                fprintf('Rotary encoder says: %s', status);
            end
        end
        
        % getX
        % returns the current X coordinate
        function x = getX(RE)
            cmd = 'x';
            RE.sendcmd(cmd);
            x = RE.receive();
        end
        
        % getY
        % returns the current Y coordinate
        function y = getY(RE)
            cmd = 'y';
            RE.sendcmd(cmd);
            y = RE.receive();
        end
        
        % getXY
        % returns the current X and Y coordinate
        function [x, y] = getXY(RE)
            cmd = 'z';
            RE.sendcmd(cmd);
            xy = sscanf(RE.receive(), '%i,%i');
            
            x = xy(1);
            y = xy(2);
        end
        
        % getXYt
        % returns the current X and Y coordinate
        function [x, y, t] = getXYt(RE)
            cmd = 'a';
            RE.sendcmd(cmd);
            xyt = sscanf(RE.receive(), '%i,%i,%i');
            
            x = xyt(1);
            y = xyt(2);
            t = xyt(3);
        end
        
        % resetX
        % Resets the X coordinate
        function resetX(RE)
            cmd = 'X';
            RE.sendcmd(cmd);
        end
        
        % resetY
        % Resets the Y coordinate
        function resetY(RE)
            cmd = 'Y';
            RE.sendcmd(cmd);
        end
        
        % resetXY
        % Reset both the X and Y coordinate
        function resetXY(RE)
            cmd = 'Z';
            RE.sendcmd(cmd);
        end
        
        function sendcmd(RE, cmd)
            if (RE.debugmode)
                fprintf('RotaryEncoder: sending: ');
                fprintf(cmd);
                fprintf('\n');
            else
                fprintf(RE.serobj, cmd);
            end
        end
        
        function response = receive(RE)
            if (RE.debugmode)
                fprintf('RotaryEncoder: listening...');
                fprintf('\n');
                response = '';
            else
                response = fscanf(RE.serobj);
            end
        end
        
        % close
        function close(RE)
            if (not(RE.debugmode))
                fclose(RE.serobj);
                delete(RE.serobj);
            end
        end
    end
end
